var fs = require("fs"),
  path = require("path");
var ts = require("typescript");
var util = require("util");
var tjs = require("typescript-json-schema");
var dblog = require("debug")("parse");

var genJSONSchema = function(defPath, outPath) {
  const settings = { required: true };
  const compilerOptions = { strictNullChecks: true };

  const program = tjs.getProgramFromFiles([defPath], compilerOptions);
  const schema = tjs.generateSchema(program, "*", settings);
  // console.log(schema);
  fs.writeFileSync(outPath, JSON.stringify(schema, null, 2));
};

var genConst = function(defPath, outPath) {
  var output = {
    rdx: {},
    net: {},
    mgr: {},
    enum: {}
  };

  var nextEnumValue = 1;

  const ast = ts.createSourceFile(
    "sample.ts",
    fs.readFileSync(pathDef).toString(),
    ts.ScriptTarget.ES6,
    true
  );
  ast.statements.forEach((v, k) => {
    dblog(v.name.text, k);
    if (v.kind == ts.SyntaxKind.EnumDeclaration) {
      nextEnumValue = 1;
      if (v.name.text == "reduxAction") {
        dblog("parse redux");
        v.members.forEach(m => {
          dblog("prop", m.name.text);
          let em = m.name.text.split("_");
          output.rdx[em[0]] = output.rdx[em[0]] || {};
          output.rdx[em[0]][em[1]] = em[1];
        });
      } else {
        output.enum[v.name.text] = {};
        if (
          v.initializer &&
          v.initializer.kind == ts.SyntaxKind.NumericLiteral
        ) {
          nextEnumValue = parseInt(v.initializer.text);
        }
        v.members.forEach(m => {
          dblog("prop", m.name.text);
          output.enum[v.name.text][m.name.text] = nextEnumValue++;
        });
      }
    } else if (
      v.kind == ts.SyntaxKind.InterfaceDeclaration ||
      v.kind == ts.SyntaxKind.ClassDeclaration
    ) {
      if (v.name.text == "mgrService" || v.name.text == "mgrClient") {
        dblog("parse mgr service", v.name.text);
        v.members.forEach(m => {
          dblog("method", m.name.text, m.kind);
          if (m.kind == ts.SyntaxKind.MethodSignature) {
            dblog("method", m.name.text);
            let name = m.name.text;
            output.mgr[name] = name;
          }
        });
      } else if (v.name.text == "wxdService" || v.name.text == "wxdClient") {
        dblog("parse dish service", v.name.text);
        v.members.forEach(m => {
          if (m.kind == ts.SyntaxKind.MethodSignature) {
            dblog("method", m.name.text);
            let name = m.name.text;
            output.net[name] = name;

            /*
						m.parameters.forEach(p => {
							if (p.type.kind == ts.SyntaxKind.StringKeyword) {
								// console.log('  param', p.name.text, 'string');
							} else if (p.type.kind == ts.SyntaxKind.TypeReference) {
								// console.log('  param', p.name.text);
							}
						});

						if (!m.type) {
							// console.log('  type ', 'void');
						} else if (m.type.kind == ts.SyntaxKind.TypeReference) {
							// console.log('  type ', m.type.typeName.text);
							//如果类型还有参数，那可能是个泛型类如array,map这样
							if (m.type.typeArguments) {
								let ta = m.type.typeArguments[0];
								// console.log('        arg ', ta.typeName.text);
							}
						} else if (m.type.kind == ts.SyntaxKind.TypeLiteral) {
							// console.log('  type ', 'literal');
						} else {
							console.error('unsupported return type');
						}
						*/
          }
        });
      }
    } else {
      dblog("unknown statement", v.kind);
    }
  });

  fs.writeFileSync(outPath, JSON.stringify(output, null, 2));
};

if (module.parent == undefined) {
  var pathDef = "src/protocolInterface.ts";
  var pathConst = "../server/src/protocolConst.json";
  var pathSchema = "../server/srcjs/protocolSchema.json";
  var pathConst2 = "../web/src/protocolConst.json";
  genConst(pathDef, pathConst);
  genConst(pathDef, pathConst2);
  genJSONSchema(pathDef, pathSchema);
}
